package com.erdos.common.util;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;

public class CollectionUtil {

	@SuppressWarnings("unchecked")
	public static Map group(Collection collection, String keyProperty) {
		Map map = new HashMap();
		if (collection == null || collection.isEmpty()) {
			return map;
		}

		Object bean = null;
		Object key = null;
		List groupList = null;

		Iterator iter = collection.iterator();

		while (iter.hasNext()) {
			bean = iter.next();
			try {
				key = PropertyUtils.getProperty(bean, keyProperty);
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			if (key == null) {
				continue;
			}
			if (map.containsKey(key)) {
				groupList = (List) map.get(key);
				groupList.add(bean);
			} else {
				groupList = new ArrayList();
				groupList.add(bean);
				map.put(key, groupList);
			}
		}

		return map;
	}

	@SuppressWarnings("unchecked")
	public static Map group(Collection collection, String keyProperty,
			String valueProperty) {
		Map map = new HashMap();
		if (collection == null || collection.isEmpty()) {
			return map;
		}

		Object bean = null;
		Object key = null;
		Object value = null;
		List groupList = null;

		Iterator iter = collection.iterator();

		while (iter.hasNext()) {
			bean = iter.next();
			try {
				key = PropertyUtils.getProperty(bean, keyProperty);
				value = PropertyUtils.getProperty(bean, valueProperty);
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			if (key == null) {
				continue;
			}
			if (map.containsKey(key)) {
				groupList = (List) map.get(key);
				groupList.add(value);
			} else {
				groupList = new ArrayList();
				groupList.add(value);
				map.put(key, groupList);
			}
		}

		return map;
	}

	@SuppressWarnings("unchecked")
	public static List group2LL(Collection collection, String rowKey,
			String colKey, Object[] cols) {
		List list = new ArrayList();

		// if srcList or rowKey is empty return an empty list
		if (collection == null || collection.isEmpty() || rowKey == null
				|| rowKey.trim().equals("")) {
			return list;
		}

		Map map = group2MM(collection, rowKey, colKey);

		list = buildLLFromMM(map, colKey, cols);

		return list;
	}

	/**
	 * @param map
	 * @param colKey
	 * @param cols
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List buildLLFromMM(Map map, String colKey, Object[] cols) {
		List list = new ArrayList();
		Iterator iter = map.values().iterator();
		// for each row
		while (iter.hasNext()) {
			List row = new ArrayList();
			Map rowMap = (Map) iter.next();
			for (int i = 0; i < cols.length; i++) {
				Object obj = rowMap.get(cols[i]);
				if (obj == null) {
					// new an instance and assign it to obj ?
				}
				row.add(obj);
			}
			list.add(row);
		}

		return list;
	}
	@SuppressWarnings("unchecked")
	public static Map group2MM(Collection collection, String rowKey,
			String colKey) {
		Map map = new LinkedHashMap(); // original HashMap

		// if any param is empty, return an empty map
		if (collection == null || collection.isEmpty() || rowKey == null
				|| rowKey.trim().equals("") || colKey == null
				|| colKey.trim().equals("")) {
			return map;
		}

		Object rowKeyObj = null;
		Object colKeyObj = null;
		Map rowMap = null;

		Iterator iter = collection.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				rowKeyObj = PropertyUtils.getProperty(bean, rowKey);
				if (rowKeyObj == null) {
					continue;
				}
				if (map.containsKey(rowKeyObj)) {
					rowMap = (Map) map.get(rowKeyObj);
					colKeyObj = PropertyUtils.getProperty(bean, colKey);
					rowMap.put(colKeyObj, bean);
				} else {
					rowMap = new LinkedHashMap(); // original HashMap
					colKeyObj = PropertyUtils.getProperty(bean, colKey);
					rowMap.put(colKeyObj, bean);
					map.put(rowKeyObj, rowMap);
				}
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		return map;
	}

	public static Long[] getLongValues(int startIndex, int endIndex) {
		int count = endIndex - startIndex + 1;
		Long[] values = new Long[count];
		for (int i = 0; i < count; i++) {
			values[i] = new Long(startIndex + i);
		}
		return values;
	}

	/**
	 * @param i
	 * @param j
	 * @return
	 */
	public static Integer[] getIntegerValues(int startIndex, int endIndex) {
		int count = endIndex - startIndex + 1;
		Integer[] values = new Integer[count];
		for (int i = 0; i < count; i++) {
			values[i] = new Integer(startIndex + i);
		}
		return values;
	}

/**
 * 
 * @param c
 * @param property
 * @param condition
 * @return
 */
	@SuppressWarnings("unchecked")
	public static List filter(Collection c, String property, Object condition) {
		List result = new ArrayList();
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				Object value = PropertyUtils.getProperty(bean, property);
				if (condition != null && condition.equals(value)) {
					result.add(bean);
				}
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	public static List filterAll(Collection collection, String property,
			Collection condition) {
		List result = new ArrayList();
		Iterator iter = collection.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				Object value = PropertyUtils.getProperty(bean, property);
				if (condition != null && condition.contains(value)) {
					result.add(bean);
				}
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	public static List filterAll(Collection collection ,String property,Map map){
		List result = new ArrayList();
		Iterator iter = collection.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				Object value = PropertyUtils.getProperty(bean, property);
				if (map != null && value != null &&map.containsKey(value)) {
					result.add(bean);
				}
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
		return result;
	}
/**
 * 
 * @param c
 * @param property
 * @param condition
 */
	@SuppressWarnings("unchecked")
	public static void exclude(Collection c, String property, Object condition) {
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				Object value = PropertyUtils.getProperty(bean, property);
				if (condition != null && condition.equals(value)) {
					iter.remove();
				}
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static void excludeAll(Collection collection, String property,
			Collection condition) {
		Iterator iter = collection.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				Object value = PropertyUtils.getProperty(bean, property);
				if (condition != null && condition.contains(value)) {
					iter.remove();
				}
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static List toList(Object[] src) {
		List result = new ArrayList();
		if (src != null) {
			for (int i = 0; i < src.length; i++) {
				result.add(src[i]);
			}
		}
		return result;
	}
	@SuppressWarnings("unchecked")
	public static Set toSet(Object[] src) {
		Set result = new HashSet();
		if (src != null) {
			for (int i = 0; i < src.length; i++) {
				result.add(src[i]);
			}
		}
		return result;
	}

	/**
	 * @param quot
	 *            TODO
	 * @param list
	 * @param string
	 * @param string2
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String getString(Collection c, String property, String quot,
			String delim) {
		StringBuffer sb = new StringBuffer();
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			Object value = bean;
			if (property != null) {
				try {
					value = PropertyUtils.getProperty(bean, property);
				} catch (IllegalAccessException e) {
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					throw new RuntimeException(e);
				} catch (NoSuchMethodException e) {
					throw new RuntimeException(e);
				}
			}
			sb.append(quot + value + quot);
			if (iter.hasNext()) {
				sb.append(delim);
			}
		}
		return sb.toString();
	}
	@SuppressWarnings("unchecked")
	/**
	 * get the propertiy of the bean in a collection
	 * 
	 * @param c
	 * @param property
	 * @return
	 */
	public static Set getProperties(Collection c, String property) {
		Set result = new HashSet();
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			Object value = bean;
			if (property != null) {
				try {
					value = PropertyUtils.getProperty(bean, property);

				} catch (IllegalAccessException e) {
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					throw new RuntimeException(e);
				} catch (NoSuchMethodException e) {
					throw new RuntimeException(e);
				}
			}
			result.add(value);
		}
		return result;
	}

	/**
	 * @param detailVos
	 * @param string
	 * @param operationId
	 */
	@SuppressWarnings("unchecked")
	public static void update(Collection c, String property, Object newValue) {
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			Object bean = iter.next();
			try {
				PropertyUtils.setProperty(bean, property, newValue);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}
	}
	@SuppressWarnings("unchecked")
	public static void sortML(Map map, Comparator valueComparator) {
		for (Iterator iter = map.values().iterator(); iter.hasNext();) {
			List valueList = (List) iter.next();
			if (valueComparator == null) {
				Collections.sort(valueList);
			} else {
				Collections.sort(valueList, valueComparator);
			}
		}
	}

	/**
	 * find the first element, with the property equals matchValue
	 * 
	 * @param c
	 * @param property
	 * @param matchValue
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Object match(Collection c, String property, Object matchValue) {
		Object result = null;
		if (c != null) {
			Iterator iter = c.iterator();
			while (iter.hasNext()) {
				Object bean = iter.next();
				Object value = bean;
				if (property != null) {
					try {
						value = PropertyUtils.getProperty(bean, property);
					} catch (IllegalAccessException e) {
						throw new RuntimeException(e);
					} catch (InvocationTargetException e) {
						throw new RuntimeException(e);
					} catch (NoSuchMethodException e) {
						throw new RuntimeException(e);
					}
				}
				if (matchValue != null && matchValue.equals(value)) {
					result = bean;
					break;
				}
			}
		}
		return result;
	}

	/**
	 * Sort the set, and return the sorted list
	 * 
	 * @param set
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List sort(Set set) {
		List list = null;
		if (set != null && set.size() > 0) {
			Object[] ojbs = set.toArray();
			Arrays.sort(ojbs);
			list = Arrays.asList(ojbs);
		} else {
			list = new ArrayList();
		}
		return list;
	}
	@SuppressWarnings("unchecked")
	public static boolean isEmpty(Collection c) {
		return c == null || c.size() == 0;
	}
	@SuppressWarnings("unchecked")
	public static Map groupBy(Collection beanCollection, String keyProp,
			String valueProp) {

		return groupBy(beanCollection, new String[] { keyProp }, mapKeyGen,
				valueProp, true);
	}

	/**
	 * Group the beans in the beanCollection, key: keyPropValues[0] + "_" + ... +
	 * keyPropValues[i] value: valuePropValue
	 * 
	 * <PRE>
	 * 
	 * beanCollection = { TestBean{prop1="1",prop2="2"},
	 * TestBean{prop1="3",prop2="4"} } CollectionUtil.groupBy(beanCollection,
	 * new String[] {"prop1", "prop2"}, "prop2") = Map { {key="1_2", value="2"},
	 * {key="3_4", value="4"}}
	 * 
	 * </PRE>
	 */
	@SuppressWarnings("unchecked")
	public static Map groupBy(Collection beanCollection, String[] keyProps,
			String valueProp) {

		return groupBy(beanCollection, keyProps, mapKeyGen, valueProp, true);
	}
	@SuppressWarnings("unchecked")
	public static Map groupBy(Collection beanCollection, String[] keyProps,
			String valueProp, boolean flat) {

		return groupBy(beanCollection, keyProps, mapKeyGen, valueProp, flat);
	}
	@SuppressWarnings("unchecked")
	public static Map groupBy(Collection beanCollection, String[] keyProps,
			MapKeyGen mapKeyGen, String valueProp, boolean flat) {

		if (isEmpty(beanCollection)) {
			return Collections.EMPTY_MAP;
		}
		Map result = (flat ? new HashMap(beanCollection.size()) : new HashMap());
		for (Iterator it = beanCollection.iterator(); it.hasNext();) {
			Object bean = it.next();
			Object[] propValues = BeanUtils.getProperty2(bean, keyProps);
			Object value = null;
			if (valueProp != null) {
				value = BeanUtils.getProperty2(bean, valueProp);
			} else {
				value = bean;
			}
			if (flat) {
				Object key = mapKeyGen.genKey(propValues);
				result.put(key, value);
			} else {
				Map currentMap = result;
				for (int j = 0; j < propValues.length; j++) {
					if (j == propValues.length - 1) {
						currentMap.put(propValues[j], value);
						break;
					}
					Map nestedMap = (Map) currentMap.get(propValues[j]);
					if (nestedMap == null) {
						nestedMap = new HashMap();
						currentMap.put(propValues[j], nestedMap);
					}
					currentMap = nestedMap;
				}
			}
		}
		return result;
	}

	public interface MapKeyGen {
		public Object genKey(Object[] values);
	}

	private static MapKeyGen mapKeyGen = new MapKeyGenDefaultImpl();

	private static class MapKeyGenDefaultImpl implements MapKeyGen {
		public Object genKey(Object[] values) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < values.length; i++) {
				if (i != 0) {
					sb.append("_");
				}
				sb.append(values[i]);
			}
			return sb.toString();
		}
	}
/**
 * return List(Map(keyName,keyProperty),(valueName,valueProperty))
 * @param collection
 * @param keyProperty
 * @param valueProperty
 * @param keyName
 * @param valueName
 * @return
 */
	@SuppressWarnings("unchecked")
	public static List getProperties(Collection collection, String keyProperty,
			String valueProperty, String keyName, String valueName) {

		List list = new ArrayList();
		if (collection == null || collection.isEmpty()) {
			return list;
		}
		Object bean = null;
		Object key = null;
		Object value = null;

		Iterator iter = collection.iterator();

		while (iter.hasNext()) {
			bean = iter.next();
			try {
				key = PropertyUtils.getProperty(bean, keyProperty);
				value = PropertyUtils.getProperty(bean, valueProperty);
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			if (key == null) {
				continue;
			}
			Map map = new HashMap();
			map.put(keyName, key);
			map.put(valueName, value);
			list.add(map);
		}

		return list;
	}
	
	
	/**
	 * to remove the multiSelectedBox selected value
	 * @param list  all of the values used to slect 
	 * @param selectedList  all of the values that have been selected
	 * @param removedId the key which accorded to remove the selected value
	 * @return  if list or selectedList value is empty,return the original value
	 * 			if not,  to remove the selected value return the removed value 
	 * @throws ServiceHintException
	 */
	@SuppressWarnings("unchecked")
	public static List  filterExistedValue(List list, String[] selectedList, String removeId){
		List tempList = new ArrayList();
		List leftExistList = new ArrayList();
		if(!list.isEmpty()&&selectedList!=null){
			
			Map map = new HashMap();
			
			for (int len=0;len<selectedList.length;len++){
				String tempId = selectedList[len];
				if(tempId!=null){
					map.put(tempId, tempId);
				}
				
			}
			int removeIndex = 0;
			for (Iterator ite = list.iterator();ite.hasNext();removeIndex++){
				Object obj = (Object)ite.next();
				String tempIds;
				try {
					tempIds = (String)PropertyUtils.getProperty(obj,removeId);
					if (map.containsKey(tempIds)){
						tempList.add(obj);
					}else{
						leftExistList.add(obj);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

		}else{
			leftExistList = list;
		}
		return leftExistList;
	}
	@SuppressWarnings("unchecked")
	public static List getSelectList(List list, String[] selectedList, String removeId){
		List tempList = new ArrayList();
		if(!list.isEmpty()&&selectedList!=null){
			Map map = new HashMap();
			
			for (int len=0;len<selectedList.length;len++){
				String tempId = selectedList[len];
				if(tempId!=null){
					map.put(tempId, tempId);
				}
			}
			int removeIndex = 0;
			for (Iterator ite = list.iterator();ite.hasNext();removeIndex++){
				Object obj = (Object)ite.next();
				String tempIds;
				try {
					tempIds = (String)PropertyUtils.getProperty(obj,removeId);
					if (map.containsKey(tempIds)){
						tempList.add(obj);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return tempList;
	}
	
	@SuppressWarnings("unchecked")
	public static void sort(List list, String property) {

		Comparator compare = CompareUtil.getComparator(property);
		
				Collections.sort(list, compare);
	}
	
	
	/**
	 * <p>Changes a set to a Stirng array.</p>
	 * @param set
	 * @return
	 */
//	public static List filterById(Collection c,String filterId){
//		List list = new ArrayList(); 
//		Iterator it = c.iterator();
//		int i=0;
//		while (it.hasNext()) {
//			
//		}
//		return result;
//	}
}
